package cn.sycoder.utils;

import cn.sycoder.config.AuthConfig;
import cn.sycoder.entity.User;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import static cn.sycoder.config.AuthConfig.getExpirationTime;
import static cn.sycoder.config.AuthConfig.getSecretKey;

/**
 * jwt 登录鉴权工具类
 */
public class JwtUtil {

    // 使用AuthConfig中的静态方法来获取密钥和过期时间
    private static final String SECRET_KEY = getSecretKey();
    private static final long EXPIRE_TIME = getExpirationTime();

    // 密钥，用于签名JWT令牌。请确保在生产环境中使用安全的密钥。
//    private static final String SECRET_KEY = "SECRET";

    // 令牌的有效期，单位为毫秒。
//    private static final long EXPIRATION_TIME = 864_000_000; // 10天的毫秒数
//    private static final long EXPIRE_TIME = 60 * 60 * 1000; // 过期时间60分钟
    /**
     * 生成带有自定义声明的JWT令牌。
     *
     * @param user   JWT的主题，通常为用户标识
     * @return 生成的JWT令牌字符串
     */
    public static String createToken(User user) {

        // 从User对象中提取userID和username
        Long userID = user.getUserId();
        String userName = user.getUserName();

        // 创建自定义声明
        Map<String, Object> claims = new HashMap<>();
        claims.put("userID", userID);
        claims.put("userName",userName);

        return Jwts.builder()
                .setClaims(claims)  // 设置自定义声明（用户ID，用户名）
                .setSubject(String.valueOf(userID))  // 设置主题（将用户ID设置为主题）
                .setIssuedAt(new Date(System.currentTimeMillis())) // 设置签发时间
                .setExpiration(new Date(System.currentTimeMillis() + EXPIRE_TIME))// 设置过期时间
                .signWith(SignatureAlgorithm.HS256, SECRET_KEY) // // 使用HS256算法和密钥进行签名
                .compact(); // 生成令牌字符串
    }

    /**
     * 解析JWT令牌，获取声明信息。
     *
     * @param token JWT令牌字符串
     * @return 声明信息的Map对象
     */
    public static Claims extractClaims(String token) {
        return Jwts.parser()
                .setSigningKey(SECRET_KEY) // 设置签名密钥
                .parseClaimsJws(token) // 解析JWT令牌
                .getBody(); // 获取声明信息的主体部分
    }

    /**
     * 从JWT令牌中提取用户名
     *
     * @param token JWT令牌字符串
     * @return 用户名
     */
    public static String extractUsername(String token) {
        return (String) extractClaims(token).get("userName"); // 从声明信息中获用户名
    }

    /**
     * 从JWT令牌中提取用户ID。
     *
     * @param token JWT令牌字符串
     * @return 用户ID
     */
    public static Long extractUserID(String token) {
        return (Long) extractClaims(token).get("userID"); // 从声明信息中获取用户ID
    }

    /**
     * 验证JWT令牌是否有效。
     *
     * @param token    JWT令牌字符串
     * @param username 预期的用户名
     * @return 如果令牌有效且用户名匹配，则返回true；否则返回false
     */
    public static boolean verifyToken(String token, String username) {
        final String extractedUsername = extractUsername(token); // 从令牌中提取用户名
        System.out.println("Extracted Username: " + extractedUsername); // 打印用户名
        System.out.println("Is Token Expired: " + isTokenExpired(token)); // 打印令牌是否过期（false 未过期）
        // 验证用户名匹配，且令牌未过期 （true && ！false）=> true
        return (extractedUsername.equals(username) && !isTokenExpired(token));
    }

    /**
     * 登录鉴权信息
     * @param token
     * @return
     */
    public static Map<String,Object> authInfo (String token) {
        final String extractedUsername = extractUsername(token); // 从令牌中提取用户名
        System.out.println("Extracted Username: " + extractedUsername); // 打印用户名
        System.out.println("Is Token Expired: " + isTokenExpired(token)); // 打印令牌是否过期（false 未过期）

        HashMap<String, Object> response = new HashMap<>();
        // 通过Linux可查看到登录用户名以及 token 是否过期
        response.put("loginUserName",extractedUsername);
        response.put("isTokenExpired",isTokenExpired(token));
        return response;
    }

    /**
     * 验证 token是否过期（true 令牌未过期）
     * @param token
     * @return
     */
    public static boolean verifyToken(String token) {
        final String extractedUsername = extractUsername(token); // 从令牌中提取用户名
        System.out.println("Extracted Username: " + extractedUsername); // 打印用户名
        System.out.println("Is Token Expired: " + isTokenExpired(token)); // 打印令牌是否过期（false 未过期）
        // 验证用户名匹配，且令牌未过期 （true && ！false）=> true
        return (!isTokenExpired(token));
    }

    /**
     * 检查JWT令牌是否过期。
     *
     * @param token JWT令牌字符串
     * @return 如果令牌已过期，则返回true；否则返回false
     */
    private static boolean isTokenExpired(String token) {
        return extractClaims(token).getExpiration().before(new Date());// 检查令牌的过期时间是否在当前时间之前
    }
}